home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / Delphi 3.0 / DATA.Z / dbcgrids.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-01-29  |  31.0 KB  |  1,123 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Delphi Visual Component Library                 }
  5. {                                                       }
  6. {       Copyright (c) 1996,97 Borland International     }
  7. {                                                       }
  8. {*******************************************************}
  9.  
  10. unit DBCGrids;
  11.  
  12. {$R-}
  13.  
  14. interface
  15.  
  16. uses SysUtils, Windows, Messages, Classes, Controls, Forms,
  17.   Graphics, Menus, DB;
  18.  
  19. type
  20.  
  21. { TDBCtrlGrid }
  22.  
  23.   TDBCtrlGrid = class;
  24.  
  25.   TDBCtrlGridLink = class(TDataLink)
  26.   private
  27.     FDBCtrlGrid: TDBCtrlGrid;
  28.   protected
  29.     procedure ActiveChanged; override;
  30.     procedure DataSetChanged; override;
  31.   public
  32.     constructor Create(DBCtrlGrid: TDBCtrlGrid);
  33.   end;
  34.  
  35.   TDBCtrlPanel = class(TWinControl)
  36.   private
  37.     FDBCtrlGrid: TDBCtrlGrid;
  38.     procedure CMControlListChange(var Message: TCMControlListChange); message CM_CONTROLLISTCHANGE;
  39.     procedure WMEraseBkgnd(var Message: TMessage); message WM_ERASEBKGND;
  40.     procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
  41.     procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST;
  42.   protected
  43.     procedure CreateParams(var Params: TCreateParams); override;
  44.     procedure PaintWindow(DC: HDC); override;
  45.   public
  46.     constructor CreateLinked(DBCtrlGrid: TDBCtrlGrid);
  47.   end;
  48.  
  49.   TDBCtrlGridOrientation = (goVertical, goHorizontal);
  50.   TDBCtrlGridBorder = (gbNone, gbRaised);
  51.   TDBCtrlGridKey = (gkNull, gkEditMode, gkPriorTab, gkNextTab, gkLeft,
  52.     gkRight, gkUp, gkDown, gkScrollUp, gkScrollDown, gkPageUp, gkPageDown,
  53.     gkHome, gkEnd, gkInsert, gkAppend, gkDelete, gkCancel);
  54.  
  55.   TPaintPanelEvent = procedure(DBCtrlGrid: TDBCtrlGrid;
  56.     Index: Integer) of object;
  57.  
  58.   TDBCtrlGrid = class(TWinControl)
  59.   private
  60.     FDataLink: TDBCtrlGridLink;
  61.     FPanel: TDBCtrlPanel;
  62.     FCanvas: TCanvas;
  63.     FColCount: Integer;
  64.     FRowCount: Integer;
  65.     FPanelWidth: Integer;
  66.     FPanelHeight: Integer;
  67.     FPanelIndex: Integer;
  68.     FPanelCount: Integer;
  69.     FBitmapCount: Integer;
  70.     FPanelBitmap: HBitmap;
  71.     FSaveBitmap: HBitmap;
  72.     FPanelDC: HDC;
  73.     FOrientation: TDBCtrlGridOrientation;
  74.     FPanelBorder: TDBCtrlGridBorder;
  75.     FAllowInsert: Boolean;
  76.     FAllowDelete: Boolean;
  77.     FShowFocus: Boolean;
  78.     FFocused: Boolean;
  79.     FClicking: Boolean;
  80.     FSelColorChanged: Boolean;
  81.     FSelectedColor: TColor;
  82.     FOnPaintPanel: TPaintPanelEvent;
  83.     function AcquireFocus: Boolean;
  84.     procedure AdjustSize;
  85.     procedure CreatePanelBitmap;
  86.     procedure DataSetChanged(Reset: Boolean);
  87.     procedure DestroyPanelBitmap;
  88.     procedure DrawPanel(DC: HDC; Index: Integer);
  89.     procedure DrawPanelBackground(DC: HDC; const R: TRect; Erase, Selected: Boolean);
  90.     function FindNext(StartControl: TWinControl; GoForward: Boolean;
  91.      var WrapFlag: Integer): TWinControl;
  92.     function GetDataSource: TDataSource;
  93.     function GetEditMode: Boolean;
  94.     function GetPanelBounds(Index: Integer): TRect;
  95.     function PointInPanel(const P: TSmallPoint): Boolean;
  96.     procedure Reset;
  97.     procedure Scroll(Inc: Integer; ScrollLock: Boolean);
  98.     procedure ScrollMessage(var Message: TWMScroll);
  99.     procedure SelectNext(GoForward: Boolean);
  100.     procedure SetColCount(Value: Integer);
  101.     procedure SetDataSource(Value: TDataSource);
  102.     procedure SetEditMode(Value: Boolean);
  103.     procedure SetOrientation(Value: TDBCtrlGridOrientation);
  104.     procedure SetPanelBorder(Value: TDBCtrlGridBorder);
  105.     procedure SetPanelHeight(Value: Integer);
  106.     procedure SetPanelIndex(Value: Integer);
  107.     procedure SetPanelWidth(Value: Integer);
  108.     procedure SetRowCount(Value: Integer);
  109.     procedure SetSelectedColor(Value: TColor);
  110.     procedure UpdateDataLinks(Control: TControl; Inserting: Boolean);
  111.     procedure UpdateScrollBar;
  112.     procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
  113.     procedure WMLButtonDblClk(var Message: TWMLButtonDblClk); message WM_LBUTTONDBLCLK;
  114.     procedure WMHScroll(var Message: TWMHScroll); message WM_HSCROLL;
  115.     procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
  116.     procedure WMEraseBkgnd(var Message: TMessage); message WM_ERASEBKGND;
  117.     procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
  118.     procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
  119.     procedure WMKillFocus(var Message: TWMKillFocus); message WM_KILLFOCUS;
  120.     procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
  121.     procedure WMSize(var Message: TMessage); message WM_SIZE;
  122.     procedure CMChildKey(var Message: TCMChildKey); message CM_CHILDKEY;
  123.     procedure CMColorChanged(var Message: TMessage); message CM_COLORCHANGED;
  124.   protected
  125.     procedure CreateParams(var Params: TCreateParams); override;
  126.     procedure CreateWnd; override;
  127.     function GetChildParent: TComponent; override;
  128.     procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
  129.     procedure PaintPanel(Index: Integer); virtual;
  130.     procedure PaintWindow(DC: HDC); override;
  131.     procedure ReadState(Reader: TReader); override;
  132.     procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
  133.     property Panel: TDBCtrlPanel read FPanel;
  134.   public
  135.     constructor Create(AOwner: TComponent); override;
  136.     destructor Destroy; override;
  137.     procedure DoKey(Key: TDBCtrlGridKey);
  138.     procedure GetTabOrderList(List: TList); override;
  139.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  140.     property Canvas: TCanvas read FCanvas;
  141.     property EditMode: Boolean read GetEditMode write SetEditMode;
  142.     property PanelCount: Integer read FPanelCount;
  143.     property PanelIndex: Integer read FPanelIndex write SetPanelIndex;
  144.   published
  145.     property Align;
  146.     property AllowDelete: Boolean read FAllowDelete write FAllowDelete default True;
  147.     property AllowInsert: Boolean read FAllowInsert write FAllowInsert default True;
  148.     property ColCount: Integer read FColCount write SetColCount;
  149.     property Color;
  150.     property DataSource: TDataSource read GetDataSource write SetDataSource;
  151.     property DragCursor;
  152.     property DragMode;
  153.     property Enabled;
  154.     property Font;
  155.     property Orientation: TDBCtrlGridOrientation read FOrientation write SetOrientation default goVertical;
  156.     property PanelBorder: TDBCtrlGridBorder read FPanelBorder write SetPanelBorder default gbRaised;
  157.     property PanelHeight: Integer read FPanelHeight write SetPanelHeight;
  158.     property PanelWidth: Integer read FPanelWidth write SetPanelWidth;
  159.     property ParentColor;
  160.     property ParentFont;
  161.     property ParentShowHint;
  162.     property PopupMenu;
  163.     property TabOrder;
  164.     property TabStop default True;
  165.     property RowCount: Integer read FRowCount write SetRowCount;
  166.     property SelectedColor: TColor read FSelectedColor write SetSelectedColor
  167.       stored FSelColorChanged default clWindow;
  168.     property ShowFocus: Boolean read FShowFocus write FShowFocus default True;
  169.     property ShowHint;
  170.     property Visible;
  171.     property OnClick;
  172.     property OnDblClick;
  173.     property OnDragDrop;
  174.     property OnDragOver;
  175.     property OnEndDrag;
  176.     property OnEnter;
  177.     property OnExit;
  178.     property OnKeyDown;
  179.     property OnKeyPress;
  180.     property OnKeyUp;
  181.     property OnMouseDown;
  182.     property OnMouseMove;
  183.     property OnMouseUp;
  184.     property OnPaintPanel: TPaintPanelEvent read FOnPaintPanel write FOnPaintPanel;
  185.     property OnStartDrag;
  186.   end;
  187.  
  188. implementation
  189.  
  190. uses DBConsts;
  191.  
  192. { TDBCtrlGridLink }
  193.  
  194. constructor TDBCtrlGridLink.Create(DBCtrlGrid: TDBCtrlGrid);
  195. begin
  196.   inherited Create;
  197.   FDBCtrlGrid := DBCtrlGrid;
  198. end;
  199.  
  200. procedure TDBCtrlGridLink.ActiveChanged;
  201. begin
  202.   FDBCtrlGrid.DataSetChanged(False);
  203. end;
  204.  
  205. procedure TDBCtrlGridLink.DataSetChanged;
  206. begin
  207.   FDBCtrlGrid.DataSetChanged(False);
  208. end;
  209.  
  210. { TDBCtrlPanel }
  211.  
  212. constructor TDBCtrlPanel.CreateLinked(DBCtrlGrid: TDBCtrlGrid);
  213. begin
  214.   inherited Create(DBCtrlGrid);
  215.   ControlStyle := [csAcceptsControls, csCaptureMouse, csClickEvents,
  216.     csDoubleClicks, csOpaque, csReplicatable];
  217.   FDBCtrlGrid := DBCtrlGrid;
  218.   Parent := DBCtrlGrid;
  219. end;
  220.  
  221. procedure TDBCtrlPanel.CreateParams(var Params: TCreateParams);
  222. begin
  223.   inherited CreateParams(Params);
  224.   with Params.WindowClass do
  225.     style := style and not (CS_HREDRAW or CS_VREDRAW);
  226. end;
  227.  
  228. procedure TDBCtrlPanel.PaintWindow(DC: HDC);
  229. var
  230.   R: TRect;
  231.   Selected: Boolean;
  232. begin
  233.   with FDBCtrlGrid do
  234.   begin
  235.     if FDataLink.Active then
  236.     begin
  237.       Selected := (FDataLink.ActiveRecord = FPanelIndex);
  238.       DrawPanelBackground(DC, Self.ClientRect, True, Selected);
  239.       FCanvas.Handle := DC;
  240.       try
  241.         FCanvas.Font := Font;
  242.         FCanvas.Brush.Style := bsSolid;
  243.         FCanvas.Brush.Color := Color;
  244.         PaintPanel(FDataLink.ActiveRecord);
  245.         if FShowFocus and FFocused and Selected then
  246.         begin
  247.           R := Self.ClientRect;
  248.           if FPanelBorder = gbRaised then InflateRect(R, -2, -2);
  249.           FCanvas.Brush.Color := Color;
  250.           FCanvas.DrawFocusRect(R);
  251.         end;
  252.       finally
  253.         FCanvas.Handle := 0;
  254.       end;
  255.     end else
  256.       DrawPanelBackground(DC, Self.ClientRect, True, csDesigning in ComponentState);
  257.   end;
  258. end;
  259.  
  260. procedure TDBCtrlPanel.CMControlListChange(var Message: TCMControlListChange);
  261. begin
  262.   FDBCtrlGrid.UpdateDataLinks(Message.Control, Message.Inserting);
  263. end;
  264.  
  265. procedure TDBCtrlPanel.WMPaint(var Message: TWMPaint);
  266. var
  267.   DC: HDC;
  268.   PS: TPaintStruct;
  269. begin
  270.   if Message.DC = 0 then
  271.   begin
  272.     FDBCtrlGrid.CreatePanelBitmap;
  273.     try
  274.       Message.DC := FDBCtrlGrid.FPanelDC;
  275.       PaintHandler(Message);
  276.       Message.DC := 0;
  277.       DC := BeginPaint(Handle, PS);
  278.       BitBlt(DC, 0, 0, Width, Height, FDBCtrlGrid.FPanelDC, 0, 0, SRCCOPY);
  279.       EndPaint(Handle, PS);
  280.     finally
  281.       FDBCtrlGrid.DestroyPanelBitmap;
  282.     end;
  283.   end else
  284.     PaintHandler(Message);
  285. end;
  286.  
  287. procedure TDBCtrlPanel.WMNCHitTest(var Message: TWMNCHitTest);
  288. begin
  289.   if csDesigning in ComponentState then
  290.     Message.Result := HTCLIENT else
  291.     Message.Result := HTTRANSPARENT;
  292. end;
  293.  
  294. procedure TDBCtrlPanel.WMEraseBkgnd(var Message: TMessage);
  295. begin
  296.   Message.Result := 1;
  297. end;
  298.  
  299. { TDBCtrlGrid }
  300.  
  301. constructor TDBCtrlGrid.Create(AOwner: TComponent);
  302. begin
  303.   inherited Create(AOwner);
  304.   ControlStyle := [csOpaque, csDoubleClicks];
  305.   TabStop := True;
  306.   FDataLink := TDBCtrlGridLink.Create(Self);
  307.   FCanvas := TCanvas.Create;
  308.   FPanel := TDBCtrlPanel.CreateLinked(Self);
  309.   FColCount := 1;
  310.   FRowCount := 3;
  311.   FPanelWidth := 200;
  312.   FPanelHeight := 72;
  313.   FPanelBorder := gbRaised;
  314.   FAllowInsert := True;
  315.   FAllowDelete := True;
  316.   FShowFocus := True;
  317.   FSelectedColor := Color;
  318.   AdjustSize;
  319. end;
  320.  
  321. destructor TDBCtrlGrid.Destroy;
  322. begin
  323.   FCanvas.Free;
  324.   FDataLink.Free;
  325.   FDataLink := nil;
  326.   inherited Destroy;
  327. end;
  328.  
  329. function TDBCtrlGrid.AcquireFocus: Boolean;
  330. begin
  331.   Result := True;
  332.   if not (Focused or EditMode) then
  333.   begin
  334.     SetFocus;
  335.     Result := Focused;
  336.   end;
  337. end;
  338.  
  339. procedure TDBCtrlGrid.AdjustSize;
  340. var
  341.   W, H: Integer;
  342. begin
  343.   W := FPanelWidth * FColCount;
  344.   H := FPanelHeight * FRowCount;
  345.   if FOrientation = goVertical then
  346.     Inc(W, GetSystemMetrics(SM_CXVSCROLL)) else
  347.     Inc(H, GetSystemMetrics(SM_CYHSCROLL));
  348.   SetBounds(Left, Top, W, H);
  349.   Reset;
  350. end;
  351.  
  352. procedure TDBCtrlGrid.CreatePanelBitmap;
  353. var
  354.   DC: HDC;
  355. begin
  356.   if FBitmapCount = 0 then
  357.   begin
  358.     DC := GetDC(0);
  359.     FPanelBitmap := CreateCompatibleBitmap(DC, FPanel.Width, FPanel.Height);
  360.     ReleaseDC(0, DC);
  361.     FPanelDC := CreateCompatibleDC(0);
  362.     FSaveBitmap := SelectObject(FPanelDC, FPanelBitmap);
  363.   end;
  364.   Inc(FBitmapCount);
  365. end;
  366.  
  367. procedure TDBCtrlGrid.CreateParams(var Params: TCreateParams);
  368. begin
  369.   inherited CreateParams(Params);
  370.   with Params do
  371.   begin
  372.     Style := Style or WS_CLIPCHILDREN;
  373.     WindowClass.style := WindowClass.style and not (CS_HREDRAW or CS_VREDRAW);
  374.   end;
  375. end;
  376.  
  377. procedure TDBCtrlGrid.CreateWnd;
  378. var
  379.   ScrollBar: Integer;
  380. begin
  381.   inherited CreateWnd;
  382.   if FOrientation = goVertical then
  383.     ScrollBar := SB_VERT else
  384.     ScrollBar := SB_HORZ;
  385.   SetScrollRange(Handle, ScrollBar, 0, 4, False);
  386. end;
  387.  
  388. procedure TDBCtrlGrid.DataSetChanged(Reset: Boolean);
  389. var
  390.   NewPanelIndex, NewPanelCount: Integer;
  391.   FocusedControl: TWinControl;
  392.   R: TRect;
  393. begin
  394.   if csDesigning in ComponentState then
  395.   begin
  396.     NewPanelIndex := 0;
  397.     NewPanelCount := 1;
  398.   end else
  399.     if FDataLink.Active then
  400.     begin
  401.       NewPanelIndex := FDataLink.ActiveRecord;
  402.       NewPanelCount := FDataLink.RecordCount;
  403.       if NewPanelCount = 0 then NewPanelCount := 1;
  404.     end else
  405.     begin
  406.       NewPanelIndex := 0;
  407.       NewPanelCount := 0;
  408.     end;
  409.   FocusedControl := nil;
  410.   R := GetPanelBounds(NewPanelIndex);
  411.   if Reset or not HandleAllocated then FPanel.BoundsRect := R else
  412.   begin
  413.     FocusedControl := FindControl(GetFocus);
  414.     if (FocusedControl <> FPanel) and FPanel.ContainsControl(FocusedControl) then
  415.       FPanel.SetFocus else
  416.       FocusedControl := nil;
  417.     if NewPanelIndex <> FPanelIndex then
  418.     begin
  419.       SetWindowPos(FPanel.Handle, 0, R.Left, R.Top, R.Right - R.Left,
  420.         R.Bottom - R.Top, SWP_NOZORDER or SWP_NOREDRAW);
  421.       if NewPanelIndex >= FPanelCount then
  422.         { Force a full redraw of all children controls when inserting a
  423.           record and the panel is in a previously unused position }
  424.         RedrawWindow(FPanel.Handle, nil, 0, RDW_INVALIDATE or RDW_ALLCHILDREN);
  425.     end;
  426.   end;
  427.   FPanelIndex := NewPanelIndex;
  428.   FPanelCount := NewPanelCount;
  429.   FPanel.Visible := FPanelCount > 0;
  430.   FPanel.Invalidate;
  431.   if not Reset then
  432.   begin
  433.     Invalidate;
  434.     Update;
  435.   end;
  436.   UpdateScrollBar;
  437.   if (FocusedControl <> nil) and not FClicking then
  438.     FocusedControl.SetFocus;
  439. end;
  440.  
  441. procedure TDBCtrlGrid.DestroyPanelBitmap;
  442. begin
  443.   Dec(FBitmapCount);
  444.   if FBitmapCount = 0 then
  445.   begin
  446.     SelectObject(FPanelDC, FSaveBitmap);
  447.     DeleteDC(FPanelDC);
  448.     DeleteObject(FPanelBitmap);
  449.   end;
  450. end;
  451.  
  452. procedure TDBCtrlGrid.DoKey(Key: TDBCtrlGridKey);
  453. var
  454.   HInc, VInc: Integer;
  455. begin
  456.   if FDataLink.Active then
  457.   begin
  458.     if FOrientation = goVertical then
  459.     begin
  460.       HInc := 1;
  461.       VInc := FColCount;
  462.     end else
  463.     begin
  464.       HInc := FRowCount;
  465.       VInc := 1;
  466.     end;
  467.     with FDataLink.DataSet do
  468.       case Key of
  469.         gkEditMode: EditMode := not EditMode;
  470.         gkPriorTab: SelectNext(False);
  471.         gkNextTab: SelectNext(True);
  472.         gkLeft: Scroll(-HInc, False);
  473.         gkRight: Scroll(HInc, False);
  474.         gkUp: Scroll(-VInc, False);
  475.         gkDown: Scroll(VInc, False);
  476.         gkScrollUp: Scroll(-VInc, True);
  477.         gkScrollDown: Scroll(VInc, True);
  478.         gkPageUp: Scroll(-FDataLink.BufferCount, True);
  479.         gkPageDown: Scroll(FDataLink.BufferCount, True);
  480.         gkHome: First;
  481.         gkEnd: Last;
  482.         gkInsert:
  483.           if FAllowInsert and CanModify then
  484.           begin
  485.             Insert;
  486.             EditMode := True;
  487.           end;
  488.         gkAppend:
  489.           if FAllowInsert and CanModify then
  490.           begin
  491.             Append;
  492.             EditMode := True;
  493.           end;
  494.         gkDelete:
  495.           if FAllowDelete and CanModify then
  496.           begin
  497.             Delete;
  498.             EditMode := False;
  499.           end;
  500.         gkCancel:
  501.           begin
  502.             Cancel;
  503.             EditMode := False;
  504.           end;
  505.       end;
  506.   end;
  507. end;
  508.  
  509. procedure TDBCtrlGrid.DrawPanel(DC: HDC; Index: Integer);
  510. var
  511.   SaveActive: Integer;
  512.   R: TRect;
  513. begin
  514.   R := GetPanelBounds(Index);
  515.   if Index < FPanelCount then
  516.   begin
  517.     SaveActive := FDataLink.ActiveRecord;
  518.     FDataLink.ActiveRecord := Index;
  519.     FPanel.PaintTo(FPanelDC, 0, 0);
  520.     FDataLink.ActiveRecord := SaveActive;
  521.   end else
  522.     DrawPanelBackground(FPanelDC, FPanel.ClientRect, True, False);
  523.   BitBlt(DC, R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top,
  524.     FPanelDC, 0, 0, SRCCOPY);
  525. end;
  526.  
  527. procedure TDBCtrlGrid.DrawPanelBackground(DC: HDC; const R: TRect;
  528.   Erase, Selected: Boolean);
  529. var
  530.   Brush: HBrush;
  531. begin
  532.   if Erase then
  533.   begin
  534.     if Selected then FPanel.Color := FSelectedColor
  535.     else FPanel.Color := Color;
  536.     Brush := CreateSolidBrush(ColorToRGB(FPanel.Color));
  537.     FillRect(DC, R, Brush);
  538.     DeleteObject(Brush);
  539.   end;
  540.   if FPanelBorder = gbRaised then
  541.     DrawEdge(DC, PRect(@R)^, BDR_RAISEDINNER, BF_RECT);
  542. end;
  543.  
  544. function TDBCtrlGrid.GetChildParent: TComponent;
  545. begin
  546.   Result := FPanel;
  547. end;
  548.  
  549. procedure TDBCtrlGrid.GetChildren(Proc: TGetChildProc; Root: TComponent);
  550. begin
  551.   FPanel.GetChildren(Proc, Root);
  552. end;
  553.  
  554. function TDBCtrlGrid.GetDataSource: TDataSource;
  555. begin
  556.   Result := FDataLink.DataSource;
  557. end;
  558.  
  559. function TDBCtrlGrid.GetEditMode: Boolean;
  560. begin
  561.   Result := not Focused and ContainsControl(FindControl(GetFocus));
  562. end;
  563.  
  564. function TDBCtrlGrid.GetPanelBounds(Index: Integer): TRect;
  565. var
  566.   Col, Row: Integer;
  567. begin
  568.   if FOrientation = goVertical then
  569.   begin
  570.     Col := Index mod FColCount;
  571.     Row := Index div FColCount;
  572.   end else
  573.   begin
  574.     Col := Index div FRowCount;
  575.     Row := Index mod FRowCount;
  576.   end;
  577.   Result.Left := FPanelWidth * Col;
  578.   Result.Top := FPanelHeight * Row;
  579.   Result.Right := Result.Left + FPanelWidth;
  580.   Result.Bottom := Result.Top + FPanelHeight;
  581. end;
  582.  
  583. procedure TDBCtrlGrid.GetTabOrderList(List: TList);
  584. begin
  585. end;
  586.  
  587. procedure TDBCtrlGrid.KeyDown(var Key: Word; Shift: TShiftState);
  588. var
  589.   GridKey: TDBCtrlGridKey;
  590. begin
  591.   inherited KeyDown(Key, Shift);
  592.   GridKey := gkNull;
  593.   case Key of
  594.     VK_LEFT: GridKey := gkLeft;
  595.     VK_RIGHT: GridKey := gkRight;
  596.     VK_UP: GridKey := gkUp;
  597.     VK_DOWN: GridKey := gkDown;
  598.     VK_PRIOR: GridKey := gkPageUp;
  599.     VK_NEXT: GridKey := gkPageDown;
  600.     VK_HOME: GridKey := gkHome;
  601.     VK_END: GridKey := gkEnd;
  602.     VK_RETURN, VK_F2: GridKey := gkEditMode;
  603.     VK_INSERT:
  604.       if GetKeyState(VK_CONTROL) >= 0 then
  605.         GridKey := gkInsert else
  606.         GridKey := gkAppend;
  607.     VK_DELETE: if GetKeyState(VK_CONTROL) < 0 then GridKey := gkDelete;
  608.     VK_ESCAPE: GridKey := gkCancel;
  609.   end;
  610.   DoKey(GridKey);
  611. end;
  612.  
  613. procedure TDBCtrlGrid.PaintWindow(DC: HDC);
  614. var
  615.   I: Integer;
  616.   Brush: HBrush;
  617. begin
  618.   if csDesigning in ComponentState then
  619.   begin
  620.     FPanel.Update;
  621.     Brush := CreateHatchBrush(HS_BDIAGONAL, ColorToRGB(clBtnShadow));
  622.     SetBkColor(DC, ColorToRGB(Color));
  623.     FillRect(DC, ClientRect, Brush);
  624.     DeleteObject(Brush);
  625.     for I := 1 to FColCount * FRowCount - 1 do
  626.       DrawPanelBackground(DC, GetPanelBounds(I), False, False);
  627.   end else
  628.   begin
  629.     CreatePanelBitmap;
  630.     try
  631.       for I := 0 to FColCount * FRowCount - 1 do
  632.         if (FPanelCount <> 0) and (I = FPanelIndex) then
  633.           FPanel.Update else
  634.           DrawPanel(DC, I);
  635.     finally
  636.       DestroyPanelBitmap;
  637.     end;
  638.   end;
  639.   // !!! Need to add code to paint the right edge too.
  640.   if HandleAllocated and (Height <> FPanel.Height * FRowCount) then
  641.   begin
  642.     Brush := CreateSolidBrush(ColorToRGB(Color));
  643.     FillRect(DC, Rect(0, FPanel.Height * FRowCount, Width, Height), Brush);
  644.     DeleteObject(Brush);
  645.   end;
  646. end;
  647.  
  648. procedure TDBCtrlGrid.PaintPanel(Index: Integer);
  649. begin
  650.   if Assigned(FOnPaintPanel) then FOnPaintPanel(Self, Index);
  651. end;
  652.  
  653. function TDBCtrlGrid.PointInPanel(const P: TSmallPoint): Boolean;
  654. begin
  655.   Result := (FPanelCount > 0) and PtInRect(GetPanelBounds(FPanelIndex),
  656.     SmallPointToPoint(P));
  657. end;
  658.  
  659. procedure TDBCtrlGrid.ReadState(Reader: TReader);
  660. begin
  661.   inherited ReadState(Reader);
  662.   FPanel.FixupTabList;
  663. end;
  664.  
  665. procedure TDBCtrlGrid.Reset;
  666. begin
  667.   if csDesigning in ComponentState then
  668.     FDataLink.BufferCount := 1 else
  669.     FDataLink.BufferCount := FColCount * FRowCount;
  670.   DataSetChanged(True);
  671. end;
  672.  
  673. procedure TDBCtrlGrid.Scroll(Inc: Integer; ScrollLock: Boolean);
  674. var
  675.   NewIndex, ScrollInc, Adjust: Integer;
  676. begin
  677.   if FDataLink.Active and (Inc <> 0) then
  678.     with FDataLink.DataSet do
  679.       if State = dsInsert then
  680.       begin
  681.         UpdateRecord;
  682.         if Modified then Post else
  683.           if (Inc < 0) or not EOF then Cancel;
  684.       end else
  685.       begin
  686.         CheckBrowseMode;
  687.         DisableControls;
  688.         try
  689.           if ScrollLock then
  690.             if Inc > 0 then
  691.               MoveBy(Inc - MoveBy(Inc + FDataLink.BufferCount - FPanelIndex - 1))
  692.             else
  693.               MoveBy(Inc - MoveBy(Inc - FPanelIndex))
  694.           else
  695.           begin
  696.             NewIndex := FPanelIndex + Inc;
  697.             if (NewIndex >= 0) and (NewIndex < FDataLink.BufferCount) then
  698.               MoveBy(Inc)
  699.             else
  700.               if MoveBy(Inc) = Inc then
  701.               begin
  702.                 if FOrientation = goVertical then
  703.                   ScrollInc := FColCount else
  704.                   ScrollInc := FRowCount;
  705.                 if Inc > 0 then
  706.                   Adjust := ScrollInc - 1 - NewIndex mod ScrollInc
  707.                 else
  708.                   Adjust := 1 - ScrollInc - (NewIndex + 1) mod ScrollInc;
  709.                 MoveBy(-MoveBy(Adjust));
  710.               end;
  711.           end;
  712.           if (Inc = 1) and EOF and FAllowInsert and CanModify then Append;
  713.         finally
  714.           EnableControls;
  715.         end;
  716.       end;
  717. end;
  718.  
  719. procedure TDBCtrlGrid.ScrollMessage(var Message: TWMScroll);
  720. var
  721.   Key: TDBCtrlGridKey;
  722. begin
  723.   if AcquireFocus then
  724.   begin
  725.     Key := gkNull;
  726.     case Message.ScrollCode of
  727.       SB_LINEUP: Key := gkScrollUp;
  728.       SB_LINEDOWN: Key := gkScrollDown;
  729.       SB_PAGEUP: Key := gkPageUp;
  730.       SB_PAGEDOWN: Key := gkPageDown;
  731.       SB_TOP: Key := gkHome;
  732.       SB_BOTTOM: Key := gkEnd;
  733.       SB_THUMBPOSITION:
  734.         begin
  735.           case Message.Pos of
  736.             0: Key := gkHome;
  737.             1: Key := gkPageUp;
  738.             3: Key := gkPageDown;
  739.             4: Key := gkEnd;
  740.           end;
  741.         end;
  742.     end;
  743.     DoKey(Key);
  744.   end;
  745. end;
  746.  
  747. function TDBCtrlGrid.FindNext(StartControl: TWinControl; GoForward: Boolean;
  748.   var WrapFlag: Integer): TWinControl;
  749. var
  750.   I, StartIndex: Integer;
  751.   List: TList;
  752. begin
  753.   List := TList.Create;
  754.   try
  755.     StartIndex := 0;
  756.     I := 0;
  757.     Result := StartControl;
  758.     FPanel.GetTabOrderList(List);
  759.     if List.Count > 0 then
  760.     begin
  761.       StartIndex := List.IndexOf(StartControl);
  762.       if StartIndex = -1 then
  763.         if GoForward then
  764.           StartIndex := List.Count - 1 else
  765.           StartIndex := 0;
  766.       I := StartIndex;
  767.       repeat
  768.         if GoForward then
  769.         begin
  770.           Inc(I);
  771.           if I = List.Count then I := 0;
  772.         end else
  773.         begin
  774.           if I = 0 then I := List.Count;
  775.           Dec(I);
  776.         end;
  777.         Result := List[I];
  778.       until (Result.CanFocus and Result.TabStop) or (I = StartIndex);
  779.     end;
  780.     WrapFlag := 0;
  781.     if GoForward then
  782.     begin
  783.       if I <= StartIndex then WrapFlag := 1;
  784.     end else
  785.     begin
  786.       if I >= StartIndex then WrapFlag := -1;
  787.     end;
  788.   finally
  789.     List.Free;
  790.   end;
  791. end;
  792.  
  793. procedure TDBCtrlGrid.SelectNext(GoForward: Boolean);
  794. var
  795.   WrapFlag: Integer;
  796.   ParentForm: TCustomForm;
  797.   ActiveControl, Control: TWinControl;
  798. begin
  799.   ParentForm := GetParentForm(Self);
  800.   if ParentForm <> nil then
  801.   begin
  802.     ActiveControl := ParentForm.ActiveControl;
  803.     if ContainsControl(ActiveControl) then
  804.     begin
  805.       Control := FindNext(ActiveControl, GoForward, WrapFlag);
  806.       FPanel.SetFocus;
  807.       try
  808.         if WrapFlag <> 0 then Scroll(WrapFlag, False);
  809.       except
  810.         ActiveControl.SetFocus;
  811.         raise;
  812.       end;
  813.       if not Control.CanFocus then
  814.         Control := FindNext(Control, GoForward, WrapFlag);
  815.       Control.SetFocus;
  816.     end;
  817.   end;
  818. end;
  819.  
  820. procedure TDBCtrlGrid.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
  821. var
  822.   ScrollWidth, ScrollHeight, NewPanelWidth, NewPanelHeight: Integer;
  823. begin
  824.   ScrollWidth := 0;
  825.   ScrollHeight := 0;
  826.   if FOrientation = goVertical then
  827.     ScrollWidth := GetSystemMetrics(SM_CXVSCROLL) else
  828.     ScrollHeight := GetSystemMetrics(SM_CYHSCROLL);
  829.   NewPanelWidth := (AWidth - ScrollWidth) div FColCount;
  830.   NewPanelHeight := (AHeight - ScrollHeight) div FRowCount;
  831.   if NewPanelWidth < 1 then NewPanelWidth := 1;
  832.   if NewPanelHeight < 1 then NewPanelHeight := 1;
  833.   if (FPanelWidth <> NewPanelWidth) or (FPanelHeight <> NewPanelHeight) then
  834.   begin
  835.     FPanelWidth := NewPanelWidth;
  836.     FPanelHeight := NewPanelHeight;
  837.     Reset;
  838.   end;
  839.   inherited SetBounds(ALeft, ATop, FPanelWidth * FColCount + ScrollWidth,
  840.     AHeight);
  841. end;
  842.  
  843. procedure TDBCtrlGrid.SetColCount(Value: Integer);
  844. begin
  845.   if Value < 1 then Value := 1;
  846.   if Value > 100 then Value := 100;
  847.   if FColCount <> Value then
  848.   begin
  849.     FColCount := Value;
  850.     AdjustSize;
  851.   end;
  852. end;
  853.  
  854. procedure TDBCtrlGrid.SetDataSource(Value: TDataSource);
  855. begin
  856.   FDataLink.DataSource := Value;
  857.   UpdateDataLinks(FPanel, True);
  858. end;
  859.  
  860. procedure TDBCtrlGrid.SetEditMode(Value: Boolean);
  861. var
  862.   Control: TWinControl;
  863. begin
  864.   if GetEditMode <> Value then
  865.     if Value then
  866.     begin
  867.       Control := FPanel.FindNextControl(nil, True, True, False);
  868.       if Control <> nil then Control.SetFocus;
  869.     end else
  870.       SetFocus;
  871. end;
  872.  
  873. procedure TDBCtrlGrid.SetOrientation(Value: TDBCtrlGridOrientation);
  874. begin
  875.   if FOrientation <> Value then
  876.   begin
  877.     FOrientation := Value;
  878.     RecreateWnd;
  879.     AdjustSize;
  880.   end;
  881. end;
  882.  
  883. procedure TDBCtrlGrid.SetPanelBorder(Value: TDBCtrlGridBorder);
  884. begin
  885.   if FPanelBorder <> Value then
  886.   begin
  887.     FPanelBorder := Value;
  888.     Invalidate;
  889.     FPanel.Invalidate;
  890.   end;
  891. end;
  892.  
  893. procedure TDBCtrlGrid.SetPanelHeight(Value: Integer);
  894. begin
  895.   if Value < 1 then Value := 1;
  896.   if Value > 65535 then Value := 65535;
  897.   if FPanelHeight <> Value then
  898.   begin
  899.     FPanelHeight := Value;
  900.     AdjustSize;
  901.   end;
  902. end;
  903.  
  904. procedure TDBCtrlGrid.SetPanelIndex(Value: Integer);
  905. begin
  906.   if FDataLink.Active and (Value < PanelCount) then
  907.     FDataLink.DataSet.MoveBy(Value - FPanelIndex);
  908. end;
  909.  
  910. procedure TDBCtrlGrid.SetPanelWidth(Value: Integer);
  911. begin
  912.   if Value < 1 then Value := 1;
  913.   if Value > 65535 then Value := 65535;
  914.   if FPanelWidth <> Value then
  915.   begin
  916.     FPanelWidth := Value;
  917.     AdjustSize;
  918.   end;
  919. end;
  920.  
  921. procedure TDBCtrlGrid.SetRowCount(Value: Integer);
  922. begin
  923.   if Value < 1 then Value := 1;
  924.   if Value > 100 then Value := 100;
  925.   if FRowCount <> Value then
  926.   begin
  927.     FRowCount := Value;
  928.     AdjustSize;
  929.   end;
  930. end;
  931.  
  932. procedure TDBCtrlGrid.SetSelectedColor(Value: TColor);
  933. begin
  934.   if Value <> FSelectedColor then
  935.   begin
  936.     FSelectedColor := Value;
  937.     FSelColorChanged := Value <> Color;
  938.     Invalidate;
  939.     FPanel.Invalidate;
  940.   end;
  941. end;
  942.  
  943. procedure TDBCtrlGrid.UpdateDataLinks(Control: TControl; Inserting: Boolean);
  944. var
  945.   I: Integer;
  946.   DataLink: TDataLink;
  947. begin
  948.   if Inserting and not (csReplicatable in Control.ControlStyle) then
  949.     DatabaseError(SNotReplicatable);
  950.   DataLink := TDataLink(Control.Perform(CM_GETDATALINK, 0, 0));
  951.   if DataLink <> nil then
  952.   begin
  953.     DataLink.DataSourceFixed := False;
  954.     if Inserting then
  955.     begin
  956.       DataLink.DataSource := DataSource;
  957.       DataLink.DataSourceFixed := True;
  958.     end;
  959.   end;
  960.   if Control is TWinControl then
  961.     with TWinControl(Control) do
  962.       for I := 0 to ControlCount - 1 do
  963.         UpdateDataLinks(Controls[I], Inserting);
  964. end;
  965.  
  966. procedure TDBCtrlGrid.UpdateScrollBar;
  967. var
  968.   ScrollBar, Pos: Integer;
  969. begin
  970.   if HandleAllocated then
  971.   begin
  972.     if FOrientation = goVertical then
  973.       ScrollBar := SB_VERT else
  974.       ScrollBar := SB_HORZ;
  975.     Pos := 0;
  976.     if FDataLink.Active and not FDataLink.DataSet.BOF then
  977.       if not FDataLink.DataSet.EOF then Pos := 2 else Pos := 4;
  978.     if GetScrollPos(Handle, ScrollBar) <> Pos then
  979.       SetScrollPos(Handle, ScrollBar, Pos, True);
  980.   end;
  981. end;
  982.  
  983. procedure TDBCtrlGrid.WMLButtonDown(var Message: TWMLButtonDown);
  984. var
  985.   I: Integer;
  986.   P: TPoint;
  987.   Window: HWnd;
  988. begin
  989.   if FDataLink.Active then
  990.   begin
  991.     P := SmallPointToPoint(Message.Pos);
  992.     for I := 0 to FPanelCount - 1 do
  993.       if (I <> FPanelIndex) and PtInRect(GetPanelBounds(I), P) then
  994.       begin
  995.         FClicking := True;
  996.         try
  997.           SetPanelIndex(I);
  998.         finally
  999.           FClicking := False;
  1000.         end;
  1001.         P := ClientToScreen(P);
  1002.         Window := WindowFromPoint(P);
  1003.         if IsChild(FPanel.Handle, Window) then
  1004.         begin
  1005.           Windows.ScreenToClient(Window, P);
  1006.           Message.Pos := PointToSmallPoint(P);
  1007.           with TMessage(Message) do SendMessage(Window, Msg, WParam, LParam);
  1008.           Exit;
  1009.         end;
  1010.         Break;
  1011.       end;
  1012.   end;
  1013.   if AcquireFocus then
  1014.   begin
  1015.     if PointInPanel(Message.Pos) then
  1016.     begin
  1017.       EditMode := False;
  1018.       Click;
  1019.     end;
  1020.     inherited;
  1021.   end;
  1022. end;
  1023.  
  1024. procedure TDBCtrlGrid.WMLButtonDblClk(var Message: TWMLButtonDblClk);
  1025. begin
  1026.   if PointInPanel(Message.Pos) then DblClick;
  1027.   inherited;
  1028. end;
  1029.  
  1030. procedure TDBCtrlGrid.WMHScroll(var Message: TWMHScroll);
  1031. begin
  1032.   ScrollMessage(Message);
  1033. end;
  1034.  
  1035. procedure TDBCtrlGrid.WMVScroll(var Message: TWMVScroll);
  1036. begin
  1037.   ScrollMessage(Message);
  1038. end;
  1039.  
  1040. procedure TDBCtrlGrid.WMEraseBkgnd(var Message: TMessage);
  1041. begin
  1042.   Message.Result := 1;
  1043. end;
  1044.  
  1045. procedure TDBCtrlGrid.WMPaint(var Message: TWMPaint);
  1046. begin
  1047.   PaintHandler(Message);
  1048. end;
  1049.  
  1050. procedure TDBCtrlGrid.WMSetFocus(var Message: TWMSetFocus);
  1051. begin
  1052.   FFocused := True;
  1053.   FPanel.Repaint;
  1054. end;
  1055.  
  1056. procedure TDBCtrlGrid.WMKillFocus(var Message: TWMKillFocus);
  1057. begin
  1058.   FFocused := False;
  1059.   FPanel.Repaint;
  1060. end;
  1061.  
  1062. procedure TDBCtrlGrid.WMGetDlgCode(var Message: TWMGetDlgCode);
  1063. begin
  1064.   Message.Result := DLGC_WANTARROWS or DLGC_WANTCHARS;
  1065. end;
  1066.  
  1067. procedure TDBCtrlGrid.WMSize(var Message: TMessage);
  1068. begin
  1069.   inherited;
  1070.   Invalidate;
  1071. end;
  1072.  
  1073. function GetShiftState: TShiftState;
  1074. begin
  1075.   Result := [];
  1076.   if GetKeyState(VK_SHIFT) < 0 then Include(Result, ssShift);
  1077.   if GetKeyState(VK_CONTROL) < 0 then Include(Result, ssCtrl);
  1078.   if GetKeyState(VK_MENU) < 0 then Include(Result, ssAlt);
  1079. end;
  1080.  
  1081. procedure TDBCtrlGrid.CMChildKey(var Message: TCMChildKey);
  1082. var
  1083.   ShiftState: TShiftState;
  1084.   GridKey: TDBCtrlGridKey;
  1085. begin
  1086.   with Message do
  1087.     if Sender <> Self then
  1088.     begin
  1089.       ShiftState := GetShiftState;
  1090.       if Assigned(OnKeyDown) then OnKeyDown(Sender, CharCode, ShiftState);
  1091.       GridKey := gkNull;
  1092.       case CharCode of
  1093.         VK_TAB:
  1094.           if not (ssCtrl in ShiftState) and
  1095.             (Sender.Perform(WM_GETDLGCODE, 0, 0) and DLGC_WANTTAB = 0) then
  1096.             if ssShift in ShiftState then
  1097.               GridKey := gkPriorTab else
  1098.               GridKey := gkNextTab;
  1099.         VK_RETURN:
  1100.           if (Sender.Perform(WM_GETDLGCODE, 0, 0) and DLGC_WANTALLKEYS = 0) then
  1101.             GridKey := gkEditMode;
  1102.         VK_F2: GridKey := gkEditMode;
  1103.         VK_ESCAPE: GridKey := gkCancel;
  1104.       end;
  1105.       if GridKey <> gkNull then
  1106.       begin
  1107.         DoKey(GridKey);
  1108.         Result := 1;
  1109.         Exit;
  1110.       end;
  1111.     end;
  1112.   inherited;
  1113. end;
  1114.  
  1115. procedure TDBCtrlGrid.CMColorChanged(var Message: TMessage);
  1116. begin
  1117.   inherited;
  1118.   if not FSelColorChanged then
  1119.     FSelectedColor := Color;
  1120. end;
  1121.  
  1122. end.
  1123.